library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_signed.ALL;
use IEEE.NUMERIC_STD.ALL;

--- Dude used for add/sub, and SLT. used for both signed and unsigned
--- 
entity add_sub is
	PORT (
	ADD_SUB_CONTROL : in STD_LOGIC;  -- subtract if 1, do not subtract if 0
	is_slt : in STD_LOGIC; -- 1 if this is slt (together with add_sub_control = '1')
	is_signed: in STD_LOGIC; -- whether signed operation or not

	A : in STD_LOGIC_VECTOR(31 downto 0); -- Operand 1
	B : in STD_LOGIC_VECTOR(31 downto 0); -- Operand 2
	
	result : out STD_LOGIC_VECTOR(31 downto 0); -- Out result
	
	carry_flag : out STD_LOGIC;
	overflow_flag : out STD_LOGIC
	);
end add_sub;

architecture Behavioral of add_sub is
	
	component Adder_32x32 is
	Port (carry_in			: in	STD_LOGIC;							  	--- '1' if we want a carry into the adder
			Arg1				: in	STD_LOGIC_VECTOR (31 downto 0); 	--- Input for additon
			Arg2				: in	STD_LOGIC_VECTOR (31 downto 0); 	--- Input for addition
			Result			: out	STD_LOGIC_VECTOR (31 downto 0); 	--- Main 32 bits of results
			carry_out		: out	STD_LOGIC								--- 
			);
	end component;
	
	signal in1 : STD_LOGIC_VECTOR (31 downto 0);
	signal in2 : STD_LOGIC_VECTOR (31 downto 0);
	signal carry_in : STD_LOGIC;	
	signal adder_out : STD_LOGIC_VECTOR (31 downto 0);
	signal adder_carry : STD_LOGIC;
	
begin
	
	main_adder : ADDER_32x32
	PORT MAP(
		arg1 => in1,
		arg2 => in2,
		
		carry_in => carry_in,
	   Result => adder_out,
		carry_out => adder_carry
	);
	
	in1 <= A;
	--result <= adder_out;
	-- control the adder
	in2 <= B xor (31 downto 0 => ADD_SUB_CONTROL);
	carry_in <= ADD_SUB_CONTROL;
	
	
	process(A, B, ADD_SUB_CONTROL, adder_out, adder_carry, is_signed, is_slt)
	begin
		
		carry_flag <= '0';
		overflow_flag <= '0';
		
		if (is_signed = '0') then -- unsigned
			if (adder_carry = '1' and add_sub_control = '0') then -- set carry flag if carry bit is set for add
				carry_flag <= '1'; 
			elsif (adder_carry ='0' and add_sub_control = '1') then -- set carry flag if carry bit is NOT set for sub
				carry_flag <= '1';
			end if;
			result <= adder_out;
		else -- signed
			if (is_slt = '0') then
				if (add_sub_control = '0') then -- add
					overflow_flag <= (adder_out(31) and not A(31) and not B(31)) or (not adder_out(31) and A(31) and B(31));
				else -- sub
					overflow_flag <= ((not A(31)) and (B(31)) and (adder_out(31))) or ((A(31)) and (not B(31)) and (not adder_out(31)));
				end if;
				result <= adder_out;
			else
				---- SLT PART
				if (A(31) = '1' and B(31) = '0') then
					-- definitely less
					result <= x"00000001";
				elsif (A(31) = '0' and B(31) = '1') then
					-- definitely more
					result <= x"00000000";
				else
					result <= x"0000000"&"000"&adder_out(31);
				end if;
			end if;
		end if;
	
		
		
	end process;
	
end Behavioral;

